///////////////////////////////////////////////////////////////////////////////
//
//                          IMPORTANT NOTICE
//
// The following open source license statement does not apply to any
// entity in the Exception List published by FMSoft.
//
// For more information, please visit:
//
// https://www.fmsoft.cn/exception-list
//
//////////////////////////////////////////////////////////////////////////////
/*
** This file is part of mg-tools, a collection of programs to convert
** and maintain the resource for MiniGUI.
**
** Copyright (C) 2010 ~ 2019, Beijing FMSoft Technologies Co., Ltd.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <string.h>

#include <minigui/common.h>
#include <minigui/gdi.h>

#include "dumpbmp.h"

#define LEN_KEY			255
#define LEN_VALUE		255

#define MAX_DUP_KEYS		10
#define NR_HASH_ENTRIES		20

static struct _STRING_HASH_ENTRY
{
	int nr_keys;
	char keys [MAX_DUP_KEYS][LEN_KEY];
	char values [MAX_DUP_KEYS][LEN_VALUE];
} _hash_table [NR_HASH_ENTRIES];

static int _hash_string (const char* key)
{
	int hval;
	const char* ptr = (const char*) key;
	char c;
	int i;

	hval = 0;
	for (i = 1; (c = *ptr++) && i <= LEN_KEY; i++)
		hval += c * i;

	return (hval % NR_HASH_ENTRIES);
}

int add_hash_entry (const char* path, const char* prefix)
{
	struct _STRING_HASH_ENTRY* entry;
	int hval = _hash_string (path);
	int key, i;

	entry = _hash_table + hval;

	if (entry->nr_keys == MAX_DUP_KEYS) {
		fprintf (stderr, "String hash table: table full for key: %s.\n", path);
		return -1;
	}

	for (i = 0; i < entry->nr_keys; i++) {
		if (strncmp (entry->keys [i], path, LEN_KEY) == 0) {
			fprintf (stderr, "String hash table: duplicated key: %s.\n", path);
			return -1;
		}
	}

	key = entry->nr_keys;
	strncpy (entry->keys [key], path, LEN_KEY);
	strncpy (entry->values [key], prefix, LEN_VALUE);
	entry->nr_keys ++;

	return 0;
}

int dump_hash_table (const char* prefix)
{
	int i, j;
	char file [MAX_PATH + 1];
	FILE* fp;
	struct _STRING_HASH_ENTRY* entry;

	sprintf (file, "%s_bmp_hash.c", prefix);

	if ((fp = fopen (file, "w+")) == NULL)
		return -1;

	fprintf (fp, "/* This file is generated by 'dumpbmp', do not edit manually. */\n\n");
	fprintf (fp, "#include <string.h>\n\n");
	fprintf (fp, "#include <minigui/common.h>\n");
	fprintf (fp, "#include <minigui/gdi.h>\n");
	fprintf (fp, "\n");

	fprintf (fp, "#define MAX_DUP_KEYS    %d\n", MAX_DUP_KEYS);
	fprintf (fp, "#define NR_HASH_ENTRIES %d\n", NR_HASH_ENTRIES);
	fprintf (fp, "\n");

	entry = _hash_table;
	for (i = 0; i < NR_HASH_ENTRIES; i ++) {
		for (j = 0; j < entry->nr_keys; j ++) {
			fprintf (fp, "#include \"%s.c\"\n", entry->values [j]);
		}
		entry ++;
	}
	fprintf (fp, "\n");

	fprintf (fp, "static struct _STRING_HASH_ENTRY\n");
	fprintf (fp, "{\n");
	fprintf (fp, "    int nr_keys;\n");
	fprintf (fp, "    const char* keys [MAX_DUP_KEYS];\n");
	fprintf (fp, "    BITMAP* bmps [MAX_DUP_KEYS];\n");
	fprintf (fp, "} %s_hash_table [NR_HASH_ENTRIES] = {\n", prefix);

	entry = _hash_table;
	for (i = 0; i < NR_HASH_ENTRIES; i ++) {
		fprintf (fp, "    {%d, {", entry->nr_keys);
		for (j = 0; j < entry->nr_keys; j ++) {
			fprintf (fp, "\"%s\", ", entry->keys [j]);
		}
		fprintf (fp, "}, {");
		for (j = 0; j < entry->nr_keys; j ++) {
			fprintf (fp, "&%s_bmp, ", entry->values [j]);
		}

		fprintf (fp, "}},\n");
		entry ++;
	}
	fprintf (fp, "};\n\n");

	fprintf (fp, "static int _hash_string (const char* key)\n");
	fprintf (fp, "{\n");
	fprintf (fp, "    int hval;\n");
	fprintf (fp, "    const char* ptr = (const char*) key;\n");
	fprintf (fp, "    char c;\n");
	fprintf (fp, "    int i;\n");
	fprintf (fp, "\n");
	fprintf (fp, "    hval = 0;\n");
	fprintf (fp, "    for (i = 1; (c = *ptr++); i++)\n");
	fprintf (fp, "        hval += c * i;\n");
	fprintf (fp, "\n");
	fprintf (fp, "    return (hval %% NR_HASH_ENTRIES);\n");
	fprintf (fp, "}\n");
	fprintf (fp, "\n");
	fprintf (fp, "PBITMAP retrive_bitmap (const char* path)\n");
	fprintf (fp, "{\n");
	fprintf (fp, "    struct _STRING_HASH_ENTRY* entry;\n");
	fprintf (fp, "    int hval = _hash_string (path);\n");
	fprintf (fp, "    int i;\n");
	fprintf (fp, "\n");
	fprintf (fp, "    entry = %s_hash_table + hval;\n", prefix);
	fprintf (fp, "    for (i = 0; i < entry->nr_keys; i++) {\n");
	fprintf (fp, "        if (strcmp (entry->keys [i], path) == 0) {\n");
	fprintf (fp, "            return entry->bmps [i];\n");
	fprintf (fp, "        }\n");
	fprintf (fp, "    }\n");
	fprintf (fp, "\n");
	fprintf (fp, "    return NULL;\n");
	fprintf (fp, "}\n\n");

	fclose (fp);

	return 0;
}

PBITMAP my_load_bitmap (const char* path)
{
	struct _STRING_HASH_ENTRY* entry;
	int hval = _hash_string (path);
	int i;

	entry = _hash_table + hval;
	for (i = 0; i < entry->nr_keys; i++) {
		if (strncmp (entry->keys [i], path, LEN_KEY) == 0) {
#if 1
			printf ("the object is %s.\n", entry->values [i]);
			return NULL;
#else
			return entry->bmps + i;
#endif
		}
	}

	return NULL;
} 

